\documentclass[a4paper]{article}
\usepackage{latexsym,amssymb,amsmath,amsbsy,amsopn,amstext,xcolor,multicol}
\usepackage{ctex,hyperref,graphicx,wrapfig,fancybox,listings}
\usepackage{pgf,pgfarrows,pgfnodes,pgfautomata,pgfheaps,pgfshade}
\usepackage[top=1in, bottom=1in, left=1.25in, right=1.25in]{geometry}
\graphicspath{{pic/}}
\title{\includegraphics[scale=0.05]{sudoku.png} \bf Sudoku Game}
\date{2017.9}
\author{计64~~翁家翌~~2016011446}
\begin{document}
\kaishu
\ttfamily
\maketitle
%\tableofcontents
%\newpage
\section{软件用途}
本软件是一个数独小游戏，使用Qt5编写，实现了数独游戏的快速生成、以及提供任意题目的解决方案。
\section{运行方式}
安装Qtcreater之后，将源代码拷贝至本机，源代码位于\url{https://git.thusaac.org/trinkle/sudoku-qt5}。运行Qtcreater直接编译即可。

Ubuntu下需要额外安装软件包qtmultimedia5-dev，进入目录之后运行 \uline{qmake -makefile;make;} 即可得到可执行文件 sudoku。
\section{功能介绍}
\subsection{使用帮助}
\begin{figure}[htp]
\centering
\includegraphics[width=0.5\linewidth]{help.png}
\caption{提示信息}
\label{fig:help}
\end{figure}

图~\ref{fig:help} 显示了关于本软件的使用帮助。它是运行软件时的最初界面，点击\uline{OK}即可进入主游戏界面。
\subsection{游戏界面}

\begin{figure}[htp]
\centering
\includegraphics[width=0.7\linewidth]{start.png}
\caption{开始界面}
\label{fig:start}
\end{figure}

图~\ref{fig:start} 显示了软件的开始游戏界面。最上方为选项栏，左侧是菜单栏，中部是数独界面，右上侧是功能栏，右中部是计时器，右下侧是数字栏。

\subsection{选项栏}
\begin{figure}[htp]
\centering
\includegraphics[width=0.5\linewidth]{title.png}
\caption{标题选项栏}
\label{fig:title}
\end{figure}

图~\ref{fig:title} 显示了软件的标题选项栏，{\bf 有四种难度可供选择，每种难度下有内置4个关卡，并且还有按照该难度随机生成题目的选项。

最后一个选项Custom提供了输入题目的功能，该软件能够给出用户提供题目的解答。}
\subsection{菜单栏}
\begin{figure}[htp]
\centering
\includegraphics[width=0.05\linewidth]{menubar.png}
\caption{菜单栏}
\label{fig:menu}
\end{figure}

图~\ref{fig:menu} 显示了软件的左侧菜单栏，从上到下依次为：显示信息（快捷键：\uline{Alt+I}）、{\bf 暂停/继续游戏}（快捷键：\uline{空格}）、{\bf 撤销}（快捷键：\uline{Ctrl+Z}）、{\bf 重做}（快捷键：\uline{Ctrl+Y}）、回到初始题目状态、{\bf 音效开关}（快捷键：\uline{Ctrl+M}）。
\subsection{功能栏}
\begin{figure}[htp]
\centering
\includegraphics[width=0.3\linewidth]{function.png}
\caption{功能栏}
\label{fig:func}
\end{figure}

图~\ref{fig:func} 显示了软件的右上侧功能栏，从上到下依次为：开始游戏、{\bf 显示帮助}、{\bf 显示计算机给出的解答}。

显示帮助时，软件会显示一个还未被正确填上数字的格子的答案；显示帮助和解答时，均不会覆盖用户记录，下一步操作会回到点击按钮之前的状态。
\subsection{数字栏}
\begin{figure}[htp]
\centering
\includegraphics[width=0.2\linewidth]{number.png}
\caption{数字栏}
\label{fig:num}
\end{figure}

图~\ref{fig:num} 显示了软件的数字栏，点击$1\sim 9$（或者按下数字$1\sim 9$按键）即可在当前选中的格子上标记/去除一个点击的数字。第四行第一个图标为{\bf 清除一个格子内的所有数字}（快捷键：\uline{Delete}），第二个图标为{\bf 标记/取消标记一个选中的格子}（快捷键：\uline{M}）。
\subsection{数独界面}
\begin{figure}[htp]
\centering
\includegraphics[width=1\linewidth]{status.png}
\caption{运行界面}
\label{fig:status}
\end{figure}

图~\ref{fig:status} 显示了软件在游戏过程中的运行界面。在每个时刻，均有一个格子被选中，用黑框蓝色字体高亮显示。当选中的格子已经填上一个数字，那么所有相同数字的格子均会{\bf 立体高亮}显示；否则如果选中的是一个空白格子，那么与这个格子同行同列的所有格子都会被{\bf 立体高亮}显示。当前选中格子的坐标在左下角会给予显示。

如果一个格子是题目数据，那么它会被标记为黑色字体；如果一个格子里有多个数字，那么程序将会以灰色小字号在格子内显示这些数字；如果一个填写上去的数字和已有数字{\bf 发生冲突}，则{\bf 标记为红色字体}；否则标记为绿色字体。

\begin{figure}[htp]
\centering
\includegraphics[width=0.7\linewidth]{finish.png}
\caption{完成解题}
\label{fig:finish}
\end{figure}

图~\ref{fig:finish} 显示了软件在用户完成解题时的界面。

\begin{figure}[htp]
\centering
\includegraphics[width=0.7\linewidth]{solve.png}
\caption{自动解题}
\label{fig:solve}
\end{figure}

图~\ref{fig:solve} 显示了软件在Custom模式中按下 \fbox{Solve} 按钮之后的自动解题情况，黑色为用户输入数据，{\bf 左下角状态栏会显示是否多解/单解/无解，以及计算机解题的用时。}

\begin{figure}[htp]
\centering
\includegraphics[width=0.5\linewidth]{ewm.png}
\caption{有关数独算法的一个PDF}
\label{fig:ewm}
\end{figure}

\section{数独算法实现}

高中的时候仔细研究了一下数独的解法，发现Dancing Link完全可以被普通的搜索所取代。基本的思路是预处理出来一个搜索序列，然后用二进制表示的状态直接进行搜索。预处理出来的序列整体上保证是限制数目从小到大的，这样的话搜索树就会长得非常瘦，也更容易寻找到解。在\uline{[NOIP2009]靶型数独}一题中，这个方法比Dancing Link快一倍以上。并且本机测试，10000组数独题目，每组平均56.5空格，总计算时间为0.82秒。

有关这个算法的详细阐述，详见图~\ref{fig:ewm}。

\section{Qt界面实现}

界面设计的一个原则是，看起来要很清楚，感觉舒服，不要太多颜色花花绿绿的，感觉很浮夸，就像那种垃圾应用一样，玩着玩着给你开个广告。我尽量避免了给使用者留下这样的印象。

我使用了\uline{QTableWidget}创造出一个表单，再将81个\uline{QPushButton}嵌到表单里面。在设计的时候，我将所有的QpushButton的setFlat设置为True。这样的话扁平效果就能够体现。一个附带的效果就是，setFlat在True和False之间切换时，由于表单上的网格线，会使整个界面产生3D立体效果（误打误撞(x）。

有一个问题困扰了我很久：QPushButton在设置成扁平化之后，在选中的时候会出现蓝色的选中框，并且会影响上下左右键的原始操作。解决方案是将{\bf 所有的}QPushButton的setFocusPolicy改成\uline{Qt::NoFocus}即可。

在每次用户产生鼠标/键盘事件时，由于无需考虑界面的实现效率，因此为了方便，每个事件产生之后都会重新刷新一遍整个界面；并且一个好处就是，可以在刷新的时候顺便更新历史版本记录。

界面设计的另一个原则就是用户友好，每种操作既可以用鼠标也可以用键盘，在撤销/恢复/显示提示/显示解答/回到最初的时候都不会丢失之前的数据，所有历史数据都存储在一个\uline{QVector}中，每次要撤销/重做的时候直接移动指针，不会将原来已经在QVector中的数据删除，新一步的操作会append到QVector中，此时再使用撤销操作会回到上一次撤销前的状态。

在Qt程序中，我保存了四个$9\times 9$的数组，分别为：题目，解答，用户数字数据和用户标记数据。

代码很丑啊我只把数独算法和ui隔离开了，一点也不OO是吧但是写得爽233。
\end{document}